/*
 * Mediator.java
 *
 * Copyright 2007, 2008 Tiberiumlabs
 *
 * This file is part of Tiberiumlabs Lailaps.
 *
 * Tiberiumlabs Lailaps is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tiberiumlabs Lailaps is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.tiberiumlabs.lailaps;

import java.util.Arrays;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.tiberiumlabs.lailaps.actions.ActionFactory;
import org.tiberiumlabs.lailaps.gui.GUIBuilder;
import org.tiberiumlabs.lailaps.list.DownloadsListModel;
import org.tiberiumlabs.lailaps.settings.NetworkSettings;
import org.tiberiumlabs.lailaps.settings.Settings;
import org.tiberiumlabs.lailaps.threads.ThreadsMap;
import org.tiberiumlabs.lailaps.toolkit.Constants;
import org.tiberiumlabs.lailaps.toolkit.StateManager;

/**
 * Singleton class to contain all other single-instance objects.
 *
 * @author <a href="mailto:paranoid.tiberiumlabs@gmail.com">Paranoid</a>
 */
public class Mediator {

    private static final Log LOG = LogFactory.getLog(Mediator.class);

    // <editor-fold defaultstate="collapsed" desc=" Singleton implementation ">
    private Mediator() {
    }

    private static final Mediator instance = new Mediator();
    public static final Mediator getMediator() {
        return instance;
    }
    // </editor-fold>

    private GUIBuilder guiBuilder = null;
    public synchronized GUIBuilder getGuiBuilder() {
        if (guiBuilder == null) {
            guiBuilder = new GUIBuilder() {};
        }
        return guiBuilder;
    }

    private ActionFactory actionFactory = null;
    public synchronized ActionFactory getActionFactory() {
        if (actionFactory == null) {
            actionFactory = new ActionFactory() {};
        }
        return actionFactory;
    }

    private DownloadsListModel downloadsListModel = new DownloadsListModel() {};
    public DownloadsListModel getDownloadsListModel() {
        return downloadsListModel;
    }

    private Header[] headers = {new Header("Accept", "*/*"), new Header("Cache-Control", "no-cache")};
    /**
     * method to generate Http request headers. generate it once and use for all downloads.
     * @return array of Http request headers
     */
    public Header[] getHttpRequestHeaders() {
        return headers;
    }

    private HttpClient httpClient = null;
    /**
     * generate instance of HttpClient. one client is usable for all application.
     * @return HttpClient for all application.
     */
    public synchronized HttpClient getHttpClient() {
        if (httpClient == null) {

            NetworkSettings netSettings = Settings.getNetworkSettings();

            MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
            int max = netSettings.getMaxWorkingThreads();
            manager.getParams().setDefaultMaxConnectionsPerHost(max);
            manager.getParams().setMaxTotalConnections(max);
            manager.getParams().setSoTimeout(netSettings.getHttpTimeout());
            httpClient = new HttpClient(manager);

            HttpClientParams params = httpClient.getParams();
            params.setParameter(HttpMethodParams.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

            params.setParameter(HttpMethodParams.USER_AGENT, netSettings.getUserAgent());
            params.setSoTimeout(netSettings.getHttpTimeout());

            params.setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, Arrays.asList(new String[] {AuthPolicy.BASIC, AuthPolicy.DIGEST}));

            // <editor-fold defaultstate="collapsed" desc=" configure proxy ">
            if (netSettings.isProxyEnabled() && netSettings.getProxyType() == Constants.PROXY_TYPE_HTTP) {
                httpClient.getHostConfiguration().setProxy(netSettings.getProxyHost(), netSettings.getProxyPort());
                Protocol.registerProtocol("ftp", new Protocol("ftp", new DefaultProtocolSocketFactory(), 21));
                if (netSettings.isProxyNeedAuthorization()) {
                    httpClient.getState().setProxyCredentials(new AuthScope(netSettings.getProxyHost(), netSettings.getProxyPort(), AuthScope.ANY_REALM),
                            new UsernamePasswordCredentials(netSettings.getProxyLogin(), netSettings.getProxyPassword()));
                }
            }
            // </editor-fold>

            LOG.info("HttpClient created...");

        }
        return httpClient;
    }
    public synchronized void shutdownHttpClient() {
        if (httpClient != null) {
            MultiThreadedHttpConnectionManager.shutdownAll();
            httpClient = null;
            LOG.info("HttpClient shutdowned...");
        }
    }

    private ThreadsMap threadsMap = null;
    public synchronized ThreadsMap getThreadsMap() {
        if (threadsMap == null) {
            threadsMap = new ThreadsMap() {};
        }
        return threadsMap;
    }

    private StateManager stateManager = null;
    /**
     * @return StateManager with all state counters
     */
    public synchronized StateManager getStateManager() {
        if (stateManager == null) {
            stateManager = new StateManager() {};
        }
        return stateManager;
    }

}
